﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using TianShu.Application.Dtos;
using TianShu.Data;
using TianShu.Domain;
using TianShu.Domain.Repositories;
using TianShu.EventBus.Distributed;
using TianShu.MultiTenancy;
using TianShu.ObjectExtending;
using TianShu.Service;
using TianShu.Service.Dtos;
using TianShu.Service.Services.Crud;
using TianShu.TenantManagement.Dal.Abstracts.Entities;
using TianShu.TenantManagement.Dal.Abstracts.Manager;
using TianShu.TenantManagement.Service.Abstracts.TenantService.Dtos;

namespace TianShu.TenantManagement
{
    public class TenantAppService : CrudServiceImpl<TenantEntity, Guid, TenantDto, TenantCreateDto, TenantUpdateDto>, ITenantAppService
    {
        protected IRepository<TenantEntity, Guid> TenantRepository { get; }
        protected ITenantManager TenantManager { get; }
        protected IDistributedEventBus DistributedEventBus { get; }

        public TenantAppService(
            IRepository<TenantEntity, Guid> tenantRepository,
            ITenantManager tenantManager,
            IDistributedEventBus distributedEventBus)
        {
            TenantRepository = tenantRepository;
            TenantManager = tenantManager;
            DistributedEventBus = distributedEventBus;
        }

        public override async Task<PageResultDto<TenantDto>> InsertAsync(TenantCreateDto dto)
        {
            dto.ExtraProperties["ContactUserName"] = dto.ContactUserName;
            dto.ExtraProperties["ContactUserPhone"] = dto.ContactUserPhone;
            dto.ExtraProperties["ContactAddress"] = dto.ContactAddress;

            await ValidateCode(dto.Code, dto.Name);

            return await base.InsertAsync(dto);
        }
        private async Task ValidateCode(string code, string name, Guid? tenantId = null)
        {
            var codeEntity = await EntityRepository.FindAsync(e => e.Code == code || e.Name == name);
            if (codeEntity != null && codeEntity.Id != tenantId)
            {
                throw new UserFriendlyException("租户已存在");
            }
        }

        protected override async Task<ResultDto<bool>> UpdateValidAsync(TenantEntity idEntity, TenantUpdateDto dto)
        {
            dto.ExtraProperties["ContactUserName"] = dto.ContactUserName;
            dto.ExtraProperties["ContactUserPhone"] = dto.ContactUserPhone;
            dto.ExtraProperties["ContactAddress"] = dto.ContactAddress;

            await ValidateCode(dto.Code, dto.Name, idEntity.Id);

            return await base.UpdateValidAsync(idEntity, dto);
        }

        public async Task<ResultDto<TenantDto>> GetByCodeAsync(string code)
        {
            var codeEntity = await EntityRepository.FindAsync(e => e.Code == code);
            if (codeEntity == null)
            {
                return new ResultDto<TenantDto>("租户不存在");
            }
            var result = ObjectMapper.Map<TenantEntity, TenantDto>(codeEntity);
            return new ResultDto<TenantDto>(result);
        }

        public virtual async Task<PageResultDto<object>> GetDefaultConnectionStringAsync(Guid id)
        {
            var tenant = await TenantManager.FindAndConnectionStringAsync(e => e.Id == id);
            var result = tenant?.FindDefaultConnectionString();
            return new PageResultDto<object>((object)result);
        }

        public virtual async Task<PageResultDto<bool>> UpdateDefaultConnectionStringAsync(Guid id, TenantConnectionStringUpdateInput input)
        {
            var tenant = await TenantManager.FindAndConnectionStringAsync(e => e.Id == id);
            tenant.SetDefaultConnectionString(input.DefaultConnectionString);
            await TenantManager.UpdateAndConnectionStringAsync(tenant);
            return new PageResultDto<bool>(true);
        }

        public virtual async Task<PageResultDto<bool>> DeleteDefaultConnectionStringAsync(Guid id)
        {
            var tenant = await TenantManager.FindAndConnectionStringAsync(e => e.Id == id);
            tenant.RemoveDefaultConnectionString();
            await TenantManager.UpdateAndConnectionStringAsync(tenant);
            return new PageResultDto<bool>(true);
        }
    }
}
